package gui.components;

import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.net.InetAddress;
import java.net.UnknownHostException;

import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPasswordField;
import javax.swing.JTextField;

import network.client.WhiteboardClient;
import controller.Constants;
import controller.NetworkController;

/**
 * A connect dialog allows user to input his detail and server information and
 * connect to the server. This dialog will only be closed when the user is
 * successfully connected to the server.
 * 
 * @author Jie Zhao(288654)
 * 
 */
public class ConnectDialog extends JDialog {
	private static final long serialVersionUID = 1L;
	private final JLabel serverAddressLabel = new JLabel();
	private final JLabel serverPortLabel = new JLabel();
	private final JTextField tfAddress = new JTextField();
	private final JTextField tfPort = new JTextField();
	private final JButton connectButton = new JButton();
	private final JButton cancelButton = new JButton();

	private int port = 0;
	private String address = null;
	private int returnvalue = -1;
	private String username = null;
	private String password = null;

	private WhiteboardClient client = null;

	private final JLabel usernameLabel = new JLabel();
	private final JLabel passwordLabel = new JLabel();
	private final JTextField tfUsername = new JTextField();
	private final JPasswordField tfPassword = new JPasswordField();

	public ConnectDialog() {
		super();
		try {
			jbInit();
		} catch (Throwable e) {
			e.printStackTrace();
		}

	}

	private void jbInit() throws Exception {
		setTitle("Connect to Server");
		setSize(350, 240);
		setName("ConnectionDialog");
		setModal(true);
		getContentPane().setLayout(null);
		setResizable(false);

		getContentPane().add(serverAddressLabel);
		serverAddressLabel.setText("Server Address:");
		serverAddressLabel.setBounds(12, 27, 114, 16);

		getContentPane().add(serverPortLabel);
		serverPortLabel.setText("Server Port:");
		serverPortLabel.setBounds(12, 61, 77, 16);

		getContentPane().add(tfAddress);
		tfAddress.setBounds(116, 25, 218, 20);

		getContentPane().add(tfPort);
		tfPort.addKeyListener(new TfPortKeyListener());
		tfPort.setColumns(5);
		tfPort.setBounds(116, 59, 218, 20);

		getContentPane().add(connectButton);
		connectButton.addActionListener(new ConnectButtonActionListener());
		connectButton.setText("Connect");
		connectButton.setBounds(101, 178, 106, 26);

		getContentPane().add(cancelButton);
		cancelButton.addActionListener(new CancelButtonActionListener());
		cancelButton.setText("Cancel");
		cancelButton.setBounds(228, 178, 106, 26);
		final FlowLayout flowLayout = new FlowLayout();
		flowLayout.setAlignment(FlowLayout.LEADING);

		if (Constants.DEBUG) {
			tfAddress.setText("localhost");
			tfPort.setText("1234");
		}

		getContentPane().add(usernameLabel);
		usernameLabel.setText("Username:");
		usernameLabel.setBounds(12, 99, 66, 16);

		getContentPane().add(passwordLabel);
		passwordLabel.setText("Password:");
		passwordLabel.setBounds(12, 132, 66, 16);

		getContentPane().add(tfUsername);
		tfUsername.setBounds(116, 97, 218, 20);

		getContentPane().add(tfPassword);
		tfPassword.setBounds(116, 130, 218, 20);
	}

	private class TfPortKeyListener extends KeyAdapter {
		public void keyPressed(KeyEvent e) {
			tfPort_keyPressed(e);
		}
	}

	private class ConnectButtonActionListener implements ActionListener {
		public void actionPerformed(ActionEvent e) {
			connectButton_actionPerformed(e);
		}
	}

	private class CancelButtonActionListener implements ActionListener {
		public void actionPerformed(ActionEvent e) {
			cancelButton_actionPerformed(e);
		}
	}

	protected void tfPort_keyPressed(KeyEvent e) {
		char c = e.getKeyChar();
		if (e.getKeyChar() == KeyEvent.VK_ENTER) {
			connectButton_actionPerformed(null);
		} else if (!Character.isISOControl(c)
				&& !Character.isDigit(e.getKeyChar())) {
			JOptionPane.showMessageDialog(null, "Port should be digit only!");
		}
	}

	/**
	 * verify the data inputed
	 * @return
	 */
	protected boolean verify() {
		address = tfAddress.getText();
		String p = tfPort.getText();

		username = tfUsername.getText();
		password = new String(tfPassword.getPassword());
		if (address == null || p == null || address.equals("") || p.equals("")) {
			JOptionPane.showMessageDialog(null,
					"Please input server port and address before connect");
			return false;
		} else if (username == null || username.equals("")) {
			JOptionPane.showMessageDialog(null, "Please give a username");
			return false;
		} else {
			try {
				port = Integer.parseInt(p);
			} catch (Exception e) {
				JOptionPane.showMessageDialog(null,
						"Port should be number only");
				return false;
			}
			if (port < 1 || port > 65534) {
				JOptionPane.showMessageDialog(null,
						"Port range should between 1-65534");
				return false;
			}
			try {
				InetAddress.getByName(address);
			} catch (UnknownHostException e) {
				JOptionPane.showMessageDialog(null,
						"Unable to resolve server address, please check.");
				return false;
			}
			try {
				client = new WhiteboardClient();
				NetworkController.getInstance().setClient(client);
				NetworkController.getInstance().setUsername(username);
				boolean isSuccess = client.connect(address, port, username,
						password);
				if (!isSuccess) {
					JOptionPane.showMessageDialog(null,
							"You are not be able to connect to the server. Reason:"
									+ client.getReason());
					return false;
				}

			} catch (Exception e) {
				return false;
			}
		}
		return true;
	}

	@Override
	public void setVisible(boolean b) {
		if (b == true) {
			returnvalue = -1;
		}
		super.setVisible(b);
	}

	protected void connectButton_actionPerformed(ActionEvent e) {
		if (verify()) {
			this.setVisible(false);
			returnvalue = 0;
		}
	}

	protected void cancelButton_actionPerformed(ActionEvent e) {
		this.setVisible(false);
		returnvalue = 1;
	}

	public int getPort() {
		return port;
	}

	public String getAddress() {
		return address;
	}

	public int getReturnvalue() {
		return returnvalue;
	}

	public WhiteboardClient getClient() {
		return client;
	}
}
